package main

import (
	"fmt"
	"math"
	"math/rand"
	"strings"
	"time"

	// 别名导入
	str "strings"

	// 点导入（不推荐）

	// 仅初始化包
	_ "image/png"
)

// 这个文件主要用于演示包的导入和使用
// 实际的包创建和模块管理需要创建多个文件和目录

func main() {
	// ==========================================
	// 包的使用
	// ==========================================

	// 使用标准库包
	fmt.Println("标准库包的使用:")

	// math包
	fmt.Printf("Pi: %.5f\n", math.Pi)
	fmt.Printf("2的平方根: %.2f\n", math.Sqrt(2))

	// strings包
	fmt.Printf("转换为大写: %s\n", strings.ToUpper("hello"))
	fmt.Printf("包含子串: %t\n", strings.Contains("seafood", "foo"))

	// 使用别名导入的包
	fmt.Printf("使用别名导入: %s\n", str.ToLower("HELLO"))

	// 使用点导入的包（不需要包名前缀）
	//fmt.Printf("使用点导入: %.2f\n", Cos(0))

	// 初始化随机数生成器
	rand.Seed(time.Now().UnixNano())
	fmt.Printf("随机数: %d\n", rand.Intn(100))

	// ==========================================
	// 包的可见性规则
	// ==========================================

	fmt.Println("\n包的可见性规则:")

	// 公开的函数和变量（首字母大写）
	fmt.Println("math.Pi是公开的:", math.Pi)

	// 非公开的函数和变量（首字母小写）不能直接访问
	// fmt.Println(math.pi) // 错误：无法访问非公开变量

	// ==========================================
	// 自定义包的使用
	// ==========================================

	fmt.Println("\n自定义包的使用:")

	// 这里我们只能演示，因为实际创建包需要多个文件
	// 下面是一个假设的例子

	// 假设我们有一个自定义包 "calculator"
	// import "myapp/calculator"
	//
	// result := calculator.Add(5, 3)
	// fmt.Printf("5 + 3 = %d\n", result)

	// ==========================================
	// 包的初始化
	// ==========================================

	fmt.Println("\n包的初始化顺序:")
	fmt.Println("1. 首先初始化导入的包")
	fmt.Println("2. 然后初始化包级别的变量")
	fmt.Println("3. 最后执行init函数")

	// 演示init函数
	fmt.Printf("初始化生成的随机数: %d\n", randomNumber)

	// ==========================================
	// Go模块基础
	// ==========================================

	fmt.Println("\nGo模块基础:")
	fmt.Println("1. 模块是包的集合")
	fmt.Println("2. go.mod文件定义模块路径和依赖")
	fmt.Println("3. go.sum文件包含依赖的校验和")

	// 常用的模块命令
	fmt.Println("\n常用的模块命令:")
	fmt.Println("- go mod init: 初始化新模块")
	fmt.Println("- go get: 添加依赖")
	fmt.Println("- go mod tidy: 整理依赖")
	fmt.Println("- go mod vendor: 将依赖复制到vendor目录")
	fmt.Println("- go list -m all: 列出所有依赖")

	// ==========================================
	// 包的文档
	// ==========================================

	fmt.Println("\n包的文档:")
	fmt.Println("- 使用godoc工具生成文档")
	fmt.Println("- 包级别的注释应放在package语句之前")
	fmt.Println("- 导出函数的注释应以函数名开头")
	fmt.Println("- 使用go doc命令查看文档")

	// ==========================================
	// 包的组织结构
	// ==========================================

	fmt.Println("\n包的组织结构:")
	fmt.Println("1. 按功能组织包")
	fmt.Println("2. 避免循环依赖")
	fmt.Println("3. 保持包的内聚性")
	fmt.Println("4. 使用内部包控制可见性")

	// ==========================================
	// 练习
	// ==========================================

	// 注意：以下练习需要创建多个文件和目录，这里只是描述

	// 1. 创建一个名为"utils"的包，包含字符串处理函数

	// 2. 创建一个名为"geometry"的包，包含计算几何图形面积和周长的函数

	// 3. 创建一个完整的模块，包含多个相关的包

	// 4. 使用vendor目录管理依赖

	// 5. 为你的包编写文档和测试
}

// 包级别的变量
var randomNumber int

// init函数在main函数之前自动执行
func init() {
	// 初始化包级别的变量
	rand.Seed(time.Now().UnixNano())
	randomNumber = rand.Intn(100)
	fmt.Println("init函数被调用")
}

// ==========================================
// 包的创建示例
// ==========================================

/*
以下是创建和使用自定义包的步骤：

1. 创建模块
   $ mkdir mymodule
   $ cd mymodule
   $ go mod init example.com/mymodule

2. 创建包目录
   $ mkdir -p pkg/calculator

3. 在包目录中创建Go文件
   $ touch pkg/calculator/calculator.go

4. 编辑calculator.go文件
   package calculator

   // Add 返回两个整数的和
   func Add(a, b int) int {
       return a + b
   }

   // Subtract 返回两个整数的差
   func Subtract(a, b int) int {
       return a - b
   }

5. 在主程序中使用包
   package main

   import (
       "fmt"
       "example.com/mymodule/pkg/calculator"
   )

   func main() {
       sum := calculator.Add(5, 3)
       diff := calculator.Subtract(5, 3)
       fmt.Printf("5 + 3 = %d\n", sum)
       fmt.Printf("5 - 3 = %d\n", diff)
   }
*/

// ==========================================
// Go模块文件示例
// ==========================================

/*
go.mod文件示例:

module example.com/mymodule

go 1.16

require (
    github.com/gin-gonic/gin v1.7.4
    github.com/go-sql-driver/mysql v1.6.0
)

replace example.com/oldmodule => example.com/newmodule v1.0.0
*/

// ==========================================
// 内部包示例
// ==========================================

/*
内部包结构示例:

mymodule/
├── internal/       # 内部包，只能被父包及其子包导入
│   ├── auth/       # 认证相关功能
│   └── db/         # 数据库相关功能
├── pkg/            # 公开的包
│   ├── api/        # API相关功能
│   └── models/     # 数据模型
└── main.go         # 主程序
*/

// ==========================================
// 包文档示例
// ==========================================

/*
// Package calculator 提供基本的数学计算功能。
//
// 这个包包含了加、减、乘、除等基本运算，
// 以及一些更复杂的数学函数。
package calculator

// Add 返回两个整数的和。
// 这个函数接受两个int类型的参数，并返回它们的和。
func Add(a, b int) int {
    return a + b
}
*/
